home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-03-10 | 58.8 KB | 2,405 lines |
- Newsgroups: comp.sources.misc
- subject: v11i003: ephem, 2 of 7
- From: ecd@cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 11, Issue 3
- Submitted-by: ecd@cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
- Archive-name: ephem4.12/part02
-
- # This is the first line of a "shell archive" file.
- # This means it contains several files that can be extracted into
- # the current directory when run with the sh shell, as follows:
- # sh < this_file_name
- # This is file 2.
- echo x compiler.c
- sed -e 's/^X//' << 'EOFxEOF' > compiler.c
- X/* module to compile and execute a c-style arithmetic expression.
- X * public entry points are compile_expr() and execute_expr().
- X *
- X * one reason this is so nice and tight is that all opcodes are the same size
- X * (an int) and the tokens the parser returns are directly usable as opcodes,
- X * for the most part. constants and variables are compiled as an opcode
- X * with an offset into the auxiliary opcode tape, opx.
- X */
- X
- X#include <math.h>
- X#include "screen.h"
- X
- X/* parser tokens and opcodes, as necessary */
- X#define HALT 0 /* good value for HALT since program is inited to 0 */
- X/* binary operators (precedences in table, below) */
- X#define ADD 1
- X#define SUB 2
- X#define MULT 3
- X#define DIV 4
- X#define AND 5
- X#define OR 6
- X#define GT 7
- X#define GE 8
- X#define EQ 9
- X#define NE 10
- X#define LT 11
- X#define LE 12
- X/* unary op, precedence in NEG_PREC #define, below */
- X#define NEG 13
- X/* symantically operands, ie, constants, variables and all functions */
- X#define CONST 14
- X#define VAR 15
- X#define ABS 16 /* add functions if desired just like this is done */
- X/* purely tokens - never get compiled as such */
- X#define LPAREN 255
- X#define RPAREN 254
- X#define ERR (-1)
- X
- X/* precedence of each of the binary operators.
- X * in case of a tie, compiler associates left-to-right.
- X * N.B. each entry's index must correspond to its #define!
- X */
- Xstatic int precedence[] = {0,5,5,6,6,2,1,4,4,3,3,4,4};
- X#define NEG_PREC 7 /* negation is highest */
- X
- X/* execute-time operand stack */
- X#define MAX_STACK 16
- Xstatic double stack[MAX_STACK], *sp;
- X
- X/* space for compiled opcodes - the "program".
- X * opcodes go in lower 8 bits.
- X * when an opcode has an operand (as CONST and VAR) it is really in opx[] and
- X * the index is in the remaining upper bits.
- X */
- X#define MAX_PROG 32
- Xstatic int program[MAX_PROG], *pc;
- X#define OP_SHIFT 8
- X#define OP_MASK 0xff
- X
- X/* auxiliary operand info.
- X * the operands (all but lower 8 bits) of CONST and VAR are really indeces
- X * into this array. thus, no point in making this any longer than you have
- X * bits more than 8 in your machine's int to index into it, ie, make
- X * MAX_OPX <= 1 << ((sizeof(int)-1)*8)
- X * also, the fld's must refer to ones being flog'd, so not point in more
- X * of these then that might be used for plotting and srching combined.
- X */
- X#define MAX_OPX 16
- Xtypedef union {
- X double opu_f; /* value when opcode is CONST */
- X int opu_fld; /* rcfpack() of field when opcode is VAR */
- X} OpX;
- Xstatic OpX opx[MAX_OPX];
- Xstatic int opxidx;
- X
- X/* these are global just for easy/rapid access */
- Xstatic int parens_nest; /* to check that parens end up nested */
- Xstatic char *err_msg; /* caller provides storage; we point at it with this */
- Xstatic char *cexpr, *lcexpr; /* pointers that move along caller's expression */
- Xstatic int good_prog; /* != 0 when program appears to be good */
- X
- X/* compile the given c-style expression.
- X * return 0 and set good_prog if ok,
- X * else return -1 and a reason message in errbuf.
- X */
- Xcompile_expr (ex, errbuf)
- Xchar *ex;
- Xchar *errbuf;
- X{
- X int instr;
- X
- X /* init the globals.
- X * also delete any flogs used in the previous program.
- X */
- X cexpr = ex;
- X err_msg = errbuf;
- X pc = program;
- X opxidx = 0;
- X parens_nest = 0;
- X do {
- X instr = *pc++;
- X if ((instr & OP_MASK) == VAR)
- X flog_delete (opx[instr >> OP_SHIFT].opu_fld);
- X } while (instr != HALT);
- X
- X pc = program;
- X if (compile(0) == ERR) {
- X sprintf (err_msg + strlen(err_msg), " at \"%.10s\"", lcexpr);
- X good_prog = 0;
- X return (-1);
- X }
- X *pc++ = HALT;
- X good_prog = 1;
- X return (0);
- X}
- X
- X/* execute the expression previously compiled with compile_expr().
- X * return 0 with *vp set to the answer if ok, else return -1 with a reason
- X * why not message in errbuf.
- X */
- Xexecute_expr (vp, errbuf)
- Xdouble *vp;
- Xchar *errbuf;
- X{
- X int s;
- X
- X err_msg = errbuf;
- X sp = stack + MAX_STACK; /* grows towards lower addresses */
- X pc = program;
- X s = execute(vp);
- X if (s < 0)
- X good_prog = 0;
- X return (s);
- X}
- X
- X/* this is a way for the outside world to ask whether there is currently a
- X * reasonable program compiled and able to execute.
- X */
- Xprog_isgood()
- X{
- X return (good_prog);
- X}
- X
- X/* get and return the opcode corresponding to the next token.
- X * leave with lcexpr pointing at the new token, cexpr just after it.
- X * also watch for mismatches parens and proper operator/operand alternation.
- X */
- Xstatic
- Xnext_token ()
- X{
- X static char toomt[] = "More than %d terms";
- X static char badop[] = "Illegal operator";
- X int tok = ERR; /* just something illegal */
- X char c;
- X
- X while ((c = *cexpr) == ' ')
- X cexpr++;
- X lcexpr = cexpr++;
- X
- X /* mainly check for a binary operator */
- X switch (c) {
- X case '\0': --cexpr; tok = HALT; break; /* keep returning HALT */
- X case '+': tok = ADD; break; /* compiler knows when it's really unary */
- X case '-': tok = SUB; break; /* compiler knows when it's really negate */
- X case '*': tok = MULT; break;
- X case '/': tok = DIV; break;
- X case '(': parens_nest++; tok = LPAREN; break;
- X case ')':
- X if (--parens_nest < 0) {
- X sprintf (err_msg, "Too many right parens");
- X return (ERR);
- X } else
- X tok = RPAREN;
- X break;
- X case '|':
- X if (*cexpr == '|') { cexpr++; tok = OR; }
- X else { sprintf (err_msg, badop); return (ERR); }
- X break;
- X case '&':
- X if (*cexpr == '&') { cexpr++; tok = AND; }
- X else { sprintf (err_msg, badop); return (ERR); }
- X break;
- X case '=':
- X if (*cexpr == '=') { cexpr++; tok = EQ; }
- X else { sprintf (err_msg, badop); return (ERR); }
- X break;
- X case '!':
- X if (*cexpr == '=') { cexpr++; tok = NE; }
- X else { sprintf (err_msg, badop); return (ERR); }
- X break;
- X case '<':
- X if (*cexpr == '=') { cexpr++; tok = LE; }
- X else tok = LT;
- X break;
- X case '>':
- X if (*cexpr == '=') { cexpr++; tok = GE; }
- X else tok = GT;
- X break;
- X }
- X
- X if (tok != ERR)
- X return (tok);
- X
- X /* not op so check for a constant, variable or function */
- X if (isdigit(c) || c == '.') {
- X if (opxidx > MAX_OPX) {
- X sprintf (err_msg, toomt, MAX_OPX);
- X return (ERR);
- X }
- X opx[opxidx].opu_f = atof (lcexpr);
- X tok = CONST | (opxidx++ << OP_SHIFT);
- X skip_double();
- X } else if (isalpha(c)) {
- X /* check list of functions */
- X if (strncmp (lcexpr, "abs", 3) == 0) {
- X cexpr += 2;
- X tok = ABS;
- X } else {
- X /* not a function, so assume it's a variable */
- X int fld;
- X if (opxidx > MAX_OPX) {
- X sprintf (err_msg, toomt, MAX_OPX);
- X return (ERR);
- X }
- X fld = parse_fieldname ();
- X if (fld < 0) {
- X sprintf (err_msg, "Unknown field");
- X return (ERR);
- X } else {
- X if (flog_add (fld) < 0) { /* register with field logger */
- X sprintf (err_msg, "Sorry; too many fields");
- X return (ERR);
- X }
- X opx[opxidx].opu_fld = fld;
- X tok = VAR | (opxidx++ << OP_SHIFT);
- X }
- X }
- X }
- X
- X return (tok);
- X}
- X
- X/* move cexpr on past a double.
- X * allow sci notation.
- X * no need to worry about a leading '-' or '+' but allow them after an 'e'.
- X * TODO: this handles all the desired cases, but also admits a bit too much
- X * such as things like 1eee2...3. geeze; to skip a double right you almost
- X * have to go ahead and crack it!
- X */
- Xstatic
- Xskip_double()
- X{
- X int sawe = 0; /* so we can allow '-' or '+' right after an 'e' */
- X
- X while (1) {
- X char c = *cexpr;
- X if (isdigit(c) || c=='.' || (sawe && (c=='-' || c=='+'))) {
- X sawe = 0;
- X cexpr++;
- X } else if (c == 'e') {
- X sawe = 1;
- X cexpr++;
- X } else
- X break;
- X }
- X}
- X
- X/* call this whenever you want to dig out the next (sub)expression.
- X * keep compiling instructions as long as the operators are higher precedence
- X * than prec, then return that "look-ahead" token that wasn't (higher prec).
- X * if error, fill in a message in err_msg[] and return ERR.
- X */
- Xstatic
- Xcompile (prec)
- Xint prec;
- X{
- X int expect_binop = 0; /* set after we have seen any operand.
- X * used by SUB so it can tell if it really
- X * should be taken to be a NEG instead.
- X */
- X int tok = next_token ();
- X
- X while (1) {
- X int p;
- X if (tok == ERR)
- X return (ERR);
- X if (pc - program >= MAX_PROG) {
- X sprintf (err_msg, "Program is too long");
- X return (ERR);
- X }
- X
- X /* check for special things like functions, constants and parens */
- X switch (tok & OP_MASK) {
- X case HALT: return (tok);
- X case ADD:
- X if (expect_binop)
- X break; /* procede with binary addition */
- X /* just skip a unary positive(?) */
- X tok = next_token();
- X continue;
- X case SUB:
- X if (expect_binop)
- X break; /* procede with binary subtract */
- X tok = compile (NEG_PREC);
- X *pc++ = NEG;
- X expect_binop = 1;
- X continue;
- X case ABS: /* other funcs would be handled the same too ... */
- X /* eat up the function parenthesized argument */
- X if (next_token() != LPAREN || compile (0) != RPAREN) {
- X sprintf (err_msg, "Function arglist error");
- X return (ERR);
- X }
- X /* then handled same as ... */
- X case CONST: /* handled same as... */
- X case VAR:
- X *pc++ = tok;
- X tok = next_token();
- X expect_binop = 1;
- X continue;
- X case LPAREN:
- X if (compile (0) != RPAREN) {
- X sprintf (err_msg, "Unmatched left paren");
- X return (ERR);
- X }
- X tok = next_token();
- X expect_binop = 1;
- X continue;
- X case RPAREN:
- X return (RPAREN);
- X }
- X
- X /* everything else is a binary operator */
- X p = precedence[tok];
- X if (p > prec) {
- X int newtok = compile (p);
- X if (newtok == ERR)
- X return (ERR);
- X *pc++ = tok;
- X expect_binop = 1;
- X tok = newtok;
- X } else
- X return (tok);
- X }
- X}
- X
- X/* "run" the program[] compiled with compile().
- X * if ok, return 0 and the final result,
- X * else return -1 with a reason why not message in err_msg.
- X */
- Xstatic
- Xexecute(result)
- Xdouble *result;
- X{
- X int instr;
- X
- X do {
- X instr = *pc++;
- X switch (instr & OP_MASK) {
- X /* put these in numberic order so hopefully even the dumbest
- X * compiler will choose to use a jump table, not a cascade of ifs.
- X */
- X case HALT: break; /* outer loop will stop us */
- X case ADD: sp[1] = sp[1] + sp[0]; sp++; break;
- X case SUB: sp[1] = sp[1] - sp[0]; sp++; break;
- X case MULT: sp[1] = sp[1] * sp[0]; sp++; break;
- X case DIV: sp[1] = sp[1] / sp[0]; sp++; break;
- X case AND: sp[1] = sp[1] && sp[0] ? 1 : 0; sp++; break;
- X case OR: sp[1] = sp[1] || sp[0] ? 1 : 0; sp++; break;
- X case GT: sp[1] = sp[1] > sp[0] ? 1 : 0; sp++; break;
- X case GE: sp[1] = sp[1] >= sp[0] ? 1 : 0; sp++; break;
- X case EQ: sp[1] = sp[1] == sp[0] ? 1 : 0; sp++; break;
- X case NE: sp[1] = sp[1] != sp[0] ? 1 : 0; sp++; break;
- X case LT: sp[1] = sp[1] < sp[0] ? 1 : 0; sp++; break;
- X case LE: sp[1] = sp[1] <= sp[0] ? 1 : 0; sp++; break;
- X case NEG: *sp = -*sp; break;
- X case CONST: *--sp = opx[instr >> OP_SHIFT].opu_f; break;
- X case VAR:
- X if (flog_get (opx[instr >> OP_SHIFT].opu_fld, --sp) < 0) {
- X sprintf (err_msg, "Bug! VAR field not logged");
- X return (-1);
- X }
- X break;
- X case ABS: *sp = fabs (*sp); break;
- X default:
- X sprintf (err_msg, "Bug! bad opcode: 0x%x", instr);
- X return (-1);
- X }
- X if (sp < stack) {
- X sprintf (err_msg, "Runtime stack overflow");
- X return (-1);
- X } else if (sp - stack > MAX_STACK) {
- X sprintf (err_msg, "Bug! runtime stack underflow");
- X return (-1);
- X }
- X } while (instr != HALT);
- X
- X /* result should now be on top of stack */
- X if (sp != &stack[MAX_STACK - 1]) {
- X sprintf (err_msg, "Bug! stack has %d items",MAX_STACK-(sp-stack));
- X return (-1);
- X }
- X *result = *sp;
- X return (0);
- X}
- X
- Xstatic
- Xisdigit(c)
- Xchar c;
- X{
- X return (c >= '0' && c <= '9');
- X}
- X
- Xstatic
- Xisalpha (c)
- Xchar c;
- X{
- X return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
- X}
- X
- X/* starting with lcexpr pointing at a string expected to be a field name,
- X * return an rcfpack(r,c,0) of the field else -1 if bad.
- X * when return, leave lcexpr alone but move cexpr to just after the name.
- X */
- Xstatic
- Xparse_fieldname ()
- X{
- X int r = -1, c = -1; /* anything illegal */
- X char *fn = lcexpr; /* likely faster than using the global */
- X char f0, f1;
- X char *dp;
- X
- X /* search for first thing not an alpha char.
- X * leave it in f0 and leave dp pointing to it.
- X */
- X dp = fn;
- X while (isalpha(f0 = *dp))
- X dp++;
- X
- X /* crack the new field name.
- X * when done trying, leave dp pointing at first char just after it.
- X * set r and c if we recognized it.
- X */
- X if (f0 == '.') {
- X /* planet.column pair.
- X * first crack the planet portion (pointed to by fn): set r.
- X * then the second portion (pointed to by dp+1): set c.
- X */
- X f0 = fn[0];
- X f1 = fn[1];
- X switch (f0) {
- X case 'j':
- X r = R_JUPITER;
- X break;
- X case 'm':
- X if (f1 == 'a') r = R_MARS;
- X else if (f1 == 'e') r = R_MERCURY;
- X else if (f1 == 'o') r = R_MOON;
- X break;
- X case 'n':
- X r = R_NEPTUNE;
- X break;
- X case 'p':
- X r = R_PLUTO;
- X break;
- X case 's':
- X if (f1 == 'a') r = R_SATURN;
- X else if (f1 == 'u') r = R_SUN;
- X break;
- X case 'u':
- X r = R_URANUS;
- X break;
- X case 'x':
- X r = R_OBJX;
- X break;
- X case 'v':
- X r = R_VENUS;
- X break;
- X }
- X
- X /* now crack the column (stuff after the dp) */
- X dp++; /* point at good stuff just after the decimal pt */
- X f0 = dp[0];
- X f1 = dp[1];
- X switch (f0) {
- X case 'a':
- X if (f1 == 'l') c = C_ALT;
- X else if (f1 == 'z') c = C_AZ;
- X break;
- X case 'd':
- X c = C_DEC;
- X break;
- X case 'e':
- X if (f1 == 'd') c = C_EDIST;
- X else if (f1 == 'l') c = C_ELONG;
- X break;
- X case 'h':
- X if (f1 == 'l') {
- X if (dp[2] == 'a') c = C_HLAT;
- X else if (dp[2] == 'o') c = C_HLONG;
- X } else if (f1 == 'r' || f1 == 'u') c = C_TUP;
- X break;
- X case 'j':
- X c = C_JUPITER;
- X break;
- X case 'm':
- X if (f1 == 'a') c = C_MARS;
- X else if (f1 == 'e') c = C_MERCURY;
- X else if (f1 == 'o') c = C_MOON;
- X break;
- X case 'n':
- X c = C_NEPTUNE;
- X break;
- X case 'p':
- X if (f1 == 'h') c = C_PHASE;
- X else if (f1 == 'l') c = C_PLUTO;
- X break;
- X case 'r':
- X if (f1 == 'a') {
- X if (dp[2] == 'z') c = C_RISEAZ;
- X else c = C_RA;
- X } else if (f1 == 't') c = C_RISETM;
- X break;
- X case 's':
- X if (f1 == 'a') {
- X if (dp[2] == 'z') c = C_SETAZ;
- X else c = C_SATURN;
- X } else if (f1 == 'd') c = C_SDIST;
- X else if (f1 == 'i') c = C_SIZE;
- X else if (f1 == 't') c = C_SETTM;
- X else if (f1 == 'u') c = C_SUN;
- X break;
- X case 't':
- X if (f1 == 'a') c = C_TRANSALT;
- X else if (f1 == 't') c = C_TRANSTM;
- X break;
- X case 'u':
- X c = C_URANUS;
- X break;
- X case 'v':
- X if (f1 == 'e') c = C_VENUS;
- X else if (f1 == 'm') c = C_MAG;
- X break;
- X }
- X
- X /* now skip dp on past the column stuff */
- X while (isalpha(*dp))
- X dp++;
- X } else {
- X /* no decimal point; some field in the top of the screen */
- X f0 = fn[0];
- X f1 = fn[1];
- X switch (f0) {
- X case 'd':
- X if (f1 == 'a') r = R_DAWN, c = C_DAWNV;
- X else if (f1 == 'u') r = R_DUSK, c = C_DUSKV;
- X break;
- X case 'n':
- X r = R_LON, c = C_LONV;
- X break;
- X }
- X }
- X
- X cexpr = dp;
- X if (r <= 0 || c <= 0) return (-1);
- X return (rcfpack (r, c, 0));
- X}
- EOFxEOF
- len=`wc -c < compiler.c`
- if expr $len != 15015 > /dev/null
- then echo Length of compiler.c is $len but it should be 15015.
- fi
- echo x eq_ecl.c
- sed -e 's/^X//' << 'EOFxEOF' > eq_ecl.c
- X#include <stdio.h>
- X#include <math.h>
- X#include "astro.h"
- X
- X#define EQtoECL 1
- X#define ECLtoEQ (-1)
- X
- X/* given the modified Julian date, mjd, and an equitorial ra and dec, each in
- X * radians, find the corresponding geocentric ecliptic latitude, *lat, and
- X * longititude, *lng, also each in radians.
- X * correction for the effect on the angle of the obliquity due to nutation is
- X * included.
- X */
- Xeq_ecl (mjd, ra, dec, lat, lng)
- Xdouble mjd, ra, dec;
- Xdouble *lat, *lng;
- X{
- X ecleq_aux (EQtoECL, mjd, ra, dec, lng, lat);
- X}
- X
- X/* given the modified Julian date, mjd, and a geocentric ecliptic latitude,
- X * *lat, and longititude, *lng, each in radians, find the corresponding
- X * equitorial ra and dec, also each in radians.
- X * correction for the effect on the angle of the obliquity due to nutation is
- X * included.
- X */
- Xecl_eq (mjd, lat, lng, ra, dec)
- Xdouble mjd, lat, lng;
- Xdouble *ra, *dec;
- X{
- X ecleq_aux (ECLtoEQ, mjd, lng, lat, ra, dec);
- X}
- X
- Xstatic
- Xecleq_aux (sw, mjd, x, y, p, q)
- Xint sw; /* +1 for eq to ecliptic, -1 for vv. */
- Xdouble mjd, x, y; /* sw==1: x==ra, y==dec. sw==-1: x==lng, y==lat. */
- Xdouble *p, *q; /* sw==1: p==lng, q==lat. sw==-1: p==ra, q==dec. */
- X{
- X static double lastmjd; /* last mjd calculated */
- X static double seps, ceps; /* sin and cos of mean obliquity */
- X double sx, cx, sy, cy, ty;
- X
- X if (mjd != lastmjd) {
- X double eps;
- X double deps, dpsi;
- X obliquity (mjd, &eps); /* mean obliquity for date */
- X nutation (mjd, &deps, &dpsi);
- X eps += deps;
- X seps = sin(eps);
- X ceps = cos(eps);
- X lastmjd = mjd;
- X }
- X
- X sy = sin(y);
- X cy = cos(y); /* always non-negative */
- X if (fabs(cy)<1e-20) cy = 1e-20; /* insure > 0 */
- X ty = sy/cy;
- X cx = cos(x);
- X sx = sin(x);
- X *q = asin((sy*ceps)-(cy*seps*sx*sw));
- X *p = atan(((sx*ceps)+(ty*seps*sw))/cx);
- X if (cx<0) *p += PI; /* account for atan quad ambiguity */
- X range (p, 2*PI);
- X}
- EOFxEOF
- len=`wc -c < eq_ecl.c`
- if expr $len != 1891 > /dev/null
- then echo Length of eq_ecl.c is $len but it should be 1891.
- fi
- echo x flog.c
- sed -e 's/^X//' << 'EOFxEOF' > flog.c
- X/* this is a simple little package to manage the saving and retrieving of
- X * field values, which we call field logging or "flogs". a flog consists of a
- X * field location, ala rcfpack(), and its value as a double. you can reset the
- X * list of flogs, add to and remove from the list of registered fields and log
- X * a field if it has been registered.
- X *
- X * this is used by the plotting and searching facilities of ephem to maintain
- X * the values of the fields that are being plotted or used in search
- X * expressions.
- X *
- X * a field can be in use for more than one
- X * thing at a time (eg, all the X plot values may the same time field, or
- X * searching and plotting might be on at one time using the same field) so
- X * we consider the field to be in use as long a usage count is > 0.
- X */
- X
- X#include "screen.h"
- X
- X#define NFLOGS 32
- X
- Xtypedef struct {
- X int fl_usagecnt; /* number of "users" logging to this field */
- X int fl_fld; /* an rcfpack(r,c,0) */
- X double fl_val;
- X} FLog;
- X
- Xstatic FLog flog[NFLOGS];
- X
- X/* add fld to the list. if already there, just increment usage count.
- X * return 0 if ok, else -1 if no more room.
- X */
- Xflog_add (fld)
- Xint fld;
- X{
- X FLog *flp, *unusedflp = 0;
- X
- X /* scan for fld already in list, or find an unused one along the way */
- X for (flp = &flog[NFLOGS]; --flp >= flog; ) {
- X if (flp->fl_usagecnt > 0) {
- X if (flp->fl_fld == fld) {
- X flp->fl_usagecnt++;
- X return (0);
- X }
- X } else
- X unusedflp = flp;
- X }
- X if (unusedflp) {
- X unusedflp->fl_fld = fld;
- X unusedflp->fl_usagecnt = 1;
- X return (0);
- X }
- X return (-1);
- X}
- X
- X/* decrement usage count for flog for fld. if goes to 0 take it out of list.
- X * ok if not in list i guess...
- X */
- Xflog_delete (fld)
- Xint fld;
- X{
- X FLog *flp;
- X
- X for (flp = &flog[NFLOGS]; --flp >= flog; )
- X if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
- X if (--flp->fl_usagecnt <= 0) {
- X flp->fl_usagecnt = 0;
- X }
- X break;
- X }
- X}
- X
- X/* if plotting or searching is active then
- X * if rcfpack(r,c,0) is in the fld list, set its value to val.
- X * return 0 if ok, else -1 if not in list.
- X */
- Xflog_log (r, c, val)
- Xint r, c;
- Xdouble val;
- X{
- X if (plot_ison() || srch_ison()) {
- X FLog *flp;
- X int fld = rcfpack (r, c, 0);
- X for (flp = &flog[NFLOGS]; --flp >= flog; )
- X if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
- X flp->fl_val = val;
- X return(0);
- X }
- X return (-1);
- X } else
- X return (0);
- X}
- X
- X/* search for fld in list. if find it return its value.
- X * return 0 if found it, else -1 if not in list.
- X */
- Xflog_get (fld, vp)
- Xint fld;
- Xdouble *vp;
- X{
- X FLog *flp;
- X
- X for (flp = &flog[NFLOGS]; --flp >= flog; )
- X if (flp->fl_fld == fld && flp->fl_usagecnt > 0) {
- X *vp = flp->fl_val;
- X return (0);
- X }
- X return (-1);
- X}
- EOFxEOF
- len=`wc -c < flog.c`
- if expr $len != 2680 > /dev/null
- then echo Length of flog.c is $len but it should be 2680.
- fi
- echo x formats.c
- sed -e 's/^X//' << 'EOFxEOF' > formats.c
- X/* basic formating routines.
- X * all the screen oriented printing should go through here.
- X */
- X
- X#include <stdio.h>
- X#include <math.h>
- X#include "astro.h"
- X#include "screen.h"
- X
- Xextern char *strcpy();
- X
- X/* suppress screen io if this is true, but always flog stuff.
- X */
- Xstatic int f_scrnoff;
- Xf_on ()
- X{
- X f_scrnoff = 0;
- X}
- Xf_off ()
- X{
- X f_scrnoff = 1;
- X}
- X
- X/* draw n blanks at the given cursor position. */
- Xf_blanks (r, c, n)
- Xint r, c, n;
- X{
- X if (f_scrnoff)
- X return;
- X c_pos (r, c);
- X while (--n >= 0)
- X putchar (' ');
- X}
- X
- X/* print the given value, v, in "sexadecimal" format at [r,c]
- X * ie, in the form A:m.P, where A is a digits wide, P is p digits.
- X * if p == 0, then no decimal point either.
- X */
- Xf_sexad (r, c, a, p, mod, v)
- Xint r, c;
- Xint a, p; /* left space, min precision */
- Xint mod; /* don't let whole portion get this big */
- Xdouble v;
- X{
- X char astr[32], str[32];
- X long dec;
- X double frac;
- X int visneg;
- X
- X (void) flog_log (r, c, v);
- X
- X if (f_scrnoff)
- X return;
- X
- X if (v >= 0.0)
- X visneg = 0;
- X else {
- X if (v <= -0.5/60.0*pow(10.0,-1.0*p)) {
- X v = -v;
- X visneg = 1;
- X } else {
- X /* don't show as negative if less than the precision showing */
- X v = 0.0;
- X visneg = 0;
- X }
- X }
- X
- X dec = v;
- X frac = (v - dec)*60.0;
- X sprintf (str, "59.%.*s5", p, "999999999");
- X if (frac >= atof (str)) {
- X dec += 1;
- X frac = 0.0;
- X }
- X dec %= mod;
- X if (dec == 0 && visneg)
- X strcpy (str, "-0");
- X else
- X sprintf (str, "%ld", visneg ? -dec : dec);
- X
- X /* would just do this if Turbo-C 2.0 %?.0f" worked:
- X * sprintf (astr, "%*s:%0*.*f", a, str, p == 0 ? 2 : p+3, p, frac);
- X */
- X if (p == 0)
- X sprintf (astr, "%*s:%02d", a, str, (int)(frac+0.5));
- X else
- X sprintf (astr, "%*s:%0*.*f", a, str, p+3, p, frac);
- X f_string (r, c, astr);
- X}
- X
- X/* print the given value, t, in sexagesimal format at [r,c]
- X * ie, in the form T:mm:ss, where T is nd digits wide.
- X * N.B. we assume nd >= 2.
- X */
- Xf_sexag (r, c, nd, t)
- Xint r, c, nd;
- Xdouble t;
- X{
- X char tstr[32];
- X int h, m, s;
- X int tisneg;
- X
- X (void) flog_log (r, c, t);
- X if (f_scrnoff)
- X return;
- X dec_sex (t, &h, &m, &s, &tisneg);
- X if (h == 0 && tisneg)
- X sprintf (tstr, "%*s-0:%02d:%02d", nd-2, "", m, s);
- X else
- X sprintf (tstr, "%*d:%02d:%02d", nd, tisneg ? -h : h, m, s);
- X f_string (r, c, tstr);
- X}
- X
- X/* print angle ra, in radians, in ra hours as hh:mm.m at [r,c]
- X * N.B. we assume ra is >= 0.
- X */
- Xf_ra (r, c, ra)
- Xint r, c;
- Xdouble ra;
- X{
- X f_sexad (r, c, 2, 1, 24, radhr(ra));
- X}
- X
- X/* print time, t, as hh:mm:ss */
- Xf_time (r, c, t)
- Xint r, c;
- Xdouble t;
- X{
- X f_sexag (r, c, 2, t);
- X}
- X
- X/* print time, t, as +/-hh:mm:ss (don't show leading +) */
- Xf_signtime (r, c, t)
- Xint r, c;
- Xdouble t;
- X{
- X f_sexag (r, c, 3, t);
- X}
- X
- X/* print time, t, as hh:mm */
- Xf_mtime (r, c, t)
- Xint r, c;
- Xdouble t;
- X{
- X f_sexad (r, c, 2, 0, 24, t);
- X}
- X
- X/* print angle, a, in rads, as degress at [r,c] in form ddd:mm */
- Xf_angle(r, c, a)
- Xint r, c;
- Xdouble a;
- X{
- X f_sexad (r, c, 3, 0, 360, raddeg(a));
- X}
- X
- X/* print angle, a, in rads, as degress at [r,c] in form dddd:mm:ss */
- Xf_gangle(r, c, a)
- Xint r, c;
- Xdouble a;
- X{
- X f_sexag (r, c, 4, raddeg(a));
- X}
- X
- X/* print the given modified Julian date, jd, as the starting date at [r,c]
- X * in the form mm/dd/yyyy.
- X */
- Xf_date (r, c, jd)
- Xint r, c;
- Xdouble jd;
- X{
- X char dstr[32];
- X int m, y;
- X double d, tmp;
- X
- X /* shadow to the plot subsystem as years. */
- X mjd_year (jd, &tmp);
- X (void) flog_log (r, c, tmp);
- X if (f_scrnoff)
- X return;
- X
- X mjd_cal (jd, &m, &d, &y);
- X
- X sprintf (dstr, "%2d/%02d/%04d", m, (int)(d), y);
- X f_string (r, c, dstr);
- X}
- X
- Xf_char (row, col, c)
- Xint row, col;
- Xchar c;
- X{
- X if (f_scrnoff)
- X return;
- X c_pos (row, col);
- X putchar (c);
- X}
- X
- Xf_string (r, c, s)
- Xint r, c;
- Xchar *s;
- X{
- X if (f_scrnoff)
- X return;
- X c_pos (r, c);
- X fputs (s, stdout);
- X}
- X
- Xf_double (r, c, fmt, f)
- Xint r, c;
- Xchar *fmt;
- Xdouble f;
- X{
- X char str[80];
- X (void) flog_log (r, c, f);
- X sprintf (str, fmt, f);
- X f_string (r, c, str);
- X}
- X
- X/* print prompt line */
- Xf_prompt (p)
- Xchar *p;
- X{
- X c_pos (R_PROMPT, C_PROMPT);
- X c_eol ();
- X c_pos (R_PROMPT, C_PROMPT);
- X fputs (p, stdout);
- X}
- X
- X/* clear from [r,c] to end of line, if we are drawing now. */
- Xf_eol (r, c)
- Xint r, c;
- X{
- X if (!f_scrnoff) {
- X c_pos (r, c);
- X c_eol();
- X }
- X}
- X
- X/* print a message and wait for op to hit any key */
- Xf_msg (m)
- Xchar *m;
- X{
- X f_prompt (m);
- X (void) read_char();
- X}
- X
- X/* crack a line of the form X?X?X into its components,
- X * where X is an integer and ? can be any character except '0-9' or '-',
- X * such as ':' or '/'.
- X * only change those fields that are specified:
- X * eg: ::10 only changes *s
- X * 10 only changes *d
- X * 10:0 changes *d and *m
- X * if see '-' anywhere, first non-zero component will be made negative.
- X */
- Xf_sscansex (bp, d, m, s)
- Xchar *bp;
- Xint *d, *m, *s;
- X{
- X char c;
- X int *p = d;
- X int *nonzp = 0;
- X int sawneg = 0;
- X int innum = 0;
- X
- X while (c = *bp++)
- X if (c >= '0' && c <= '9') {
- X if (!innum) {
- X *p = 0;
- X innum = 1;
- X }
- X *p = *p*10 + (c - '0');
- X if (*p && !nonzp)
- X nonzp = p;
- X } else if (c == '-') {
- X sawneg = 1;
- X } else if (c != ' ') {
- X /* advance to next component */
- X p = (p == d) ? m : s;
- X innum = 0;
- X }
- X
- X if (sawneg && nonzp)
- X *nonzp = -*nonzp;
- X}
- X
- X/* crack a floating date string, bp, of the form m/d/y, where d may be a
- X * floating point number, into its components.
- X * leave any component unspecified unchanged.
- X * actually, the slashes may be anything but digits or a decimal point.
- X * this is functionally the same as f_sscansex() exept we allow for
- X * the day portion to be real, and we don't handle negative numbers.
- X * maybe someday we could make a combined one and use it everywhere.
- X */
- Xf_sscandate (bp, m, d, y)
- Xchar *bp;
- Xint *m, *y;
- Xdouble *d;
- X{
- X char *bp0, c;
- X
- X bp0 = bp;
- X while ((c = *bp++) && (c >= '0' && c <= '9'))
- X continue;
- X if (bp > bp0+1)
- X *m = atoi (bp0);
- X if (c == '\0')
- X return;
- X bp0 = bp;
- X while ((c = *bp++) && (c >= '0' && c <= '9' || c == '.'))
- X continue;
- X if (bp > bp0+1)
- X *d = atof (bp0);
- X if (c == '\0')
- X return;
- X bp0 = bp;
- X while (c = *bp++)
- X continue;
- X if (bp > bp0+1)
- X *y = atoi (bp0);
- X}
- X
- X/* just like dec_sex() but makes the first non-zero element negative if
- X * x is negative (instead of returning a sign flag).
- X */
- Xf_dec_sexsign (x, h, m, s)
- Xdouble x;
- Xint *h, *m, *s;
- X{
- X int n;
- X dec_sex (x, h, m, s, &n);
- X if (n) {
- X if (*h)
- X *h = -*h;
- X else if (*m)
- X *m = -*m;
- X else
- X *s = -*s;
- X }
- X}
- X
- X/* return 1 if bp looks like a decimal year; else 0.
- X * any number greater than 12 is assumed to be a year, or any string
- X * with exactly one decimal point, an optional minus sign, and nothing
- X * else but digits.
- X */
- Xdecimal_year (bp)
- Xchar *bp;
- X{
- X char c;
- X int ndig = 0, ndp = 0, nneg = 0, nchar = 0;
- X int n = atoi(bp);
- X
- X while (c = *bp++) {
- X nchar++;
- X if (c >= '0' && c <= '9')
- X ndig++;
- X else if (c == '.')
- X ndp++;
- X else if (c == '-')
- X nneg++;
- X }
- X
- X return (n > 12 || (ndp == 1 && nneg <= 1 && nchar == ndig+ndp+nneg));
- X}
- EOFxEOF
- len=`wc -c < formats.c`
- if expr $len != 6850 > /dev/null
- then echo Length of formats.c is $len but it should be 6850.
- fi
- echo x io.c
- sed -e 's/^X//' << 'EOFxEOF' > io.c
- X/* this file (in principle) contains all the device-dependent code for
- X * handling screen movement and reading the keyboard. public routines are:
- X * c_pos(r,c), c_erase(), c_eol();
- X * chk_char(), read_char(), read_line (buf, max); and
- X * byetty().
- X * N.B. we assume output may be performed by printf(), putchar() and
- X * fputs(stdout). since these are buffered we flush first in read_char().
- X */
- X
- X/* explanation of various conditional #define options:
- X * UNIX: uses termcap for screen management.
- X * USE_NDELAY: does non-blocking tty reads with fcntl(O_NDELAY); otherwise
- X * this is done with ioctl(..,FIONREAD..). Use which ever works on your
- X * system.
- X * TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
- X * Microsoft too.
- X * USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
- X * Mr. Doug McDonald). If your PC does not work with this, however, add
- X * "device ANSI.SYS" to your config.sys file and build ephem with
- X * USE_ANSISYS.
- X */
- X
- X#define UNIX
- X/* #define USE_NDELAY */
- X/* #define TURBO_C */
- X/* #define USE_ANSISYS */
- X
- X#include <stdio.h>
- X#include "screen.h"
- X
- X#ifdef UNIX
- X#include <sgtty.h>
- X#include <signal.h>
- X#ifdef USE_NDELAY
- X#include <fcntl.h>
- X#endif
- X
- Xextern char *tgoto();
- Xstatic char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
- Xstatic int tloaded;
- Xstatic int ttysetup;
- Xstatic struct sgttyb orig_sgtty;
- X
- X/* move cursor to row, col, 1-based.
- X * we assume this also moves a visible cursor to this location.
- X */
- Xc_pos (r, c)
- Xint r, c;
- X{
- X if (!tloaded) tload();
- X fputs (tgoto (cm, c-1, r-1), stdout);
- X}
- X
- X/* erase entire screen. */
- Xc_erase()
- X{
- X if (!tloaded) tload();
- X fputs (cl, stdout);
- X}
- X
- X/* erase to end of line */
- Xc_eol()
- X{
- X if (!tloaded) tload();
- X fputs (ce, stdout);
- X}
- X
- X#ifdef USE_NDELAY
- Xstatic char sav_char; /* one character read-ahead for chk_char() */
- X#endif
- X
- X/* return 0 if there is a char that may be read without blocking, else -1 */
- Xchk_char()
- X{
- X#ifdef USE_NDELAY
- X if (!ttysetup) setuptty();
- X if (sav_char)
- X return (0);
- X fcntl (0, F_SETFL, O_NDELAY); /* non-blocking read. FNDELAY on BSD */
- X if (read (0, &sav_char, 1) != 1)
- X sav_char = 0;
- X return (sav_char ? 0 : -1);
- X#else
- X long n;
- X if (!ttysetup) setuptty();
- X ioctl (0, FIONREAD, &n);
- X return (n > 0 ? 0 : -1);
- X#endif
- X}
- X
- X/* read the next char, blocking if necessary, and return it. don't echo.
- X * map the arrow keys if we can too into hjkl
- X */
- Xread_char()
- X{
- X char c;
- X if (!ttysetup) setuptty();
- X fflush (stdout);
- X#ifdef USE_NDELAY
- X fcntl (0, F_SETFL, 0); /* blocking read */
- X if (sav_char) {
- X c = sav_char;
- X sav_char = 0;
- X } else
- X#endif
- X read (0, &c, 1);
- X c = chk_arrow (c & 0177); /* just ASCII, please */
- X return (c);
- X}
- X
- X/* used to time out of a read */
- Xstatic got_alrm;
- Xstatic
- Xon_alrm()
- X{
- X got_alrm = 1;
- X}
- X
- X/* see if c is the first of any of the curses arrow key sequences.
- X * if it is, read the rest of the sequence, and return the hjkl code
- X * that corresponds.
- X * if no match, just return c.
- X */
- Xstatic
- Xchk_arrow (c)
- Xregister char c;
- X{
- X register char *seq;
- X
- X if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
- X || c == *(seq = kr)) {
- X char seqa[32]; /* maximum arrow escape sequence ever expected */
- X unsigned l = strlen(seq);
- X seqa[0] = c;
- X if (l > 1) {
- X extern unsigned alarm();
- X /* cautiously read rest of arrow sequence */
- X got_alrm = 0;
- X signal (SIGALRM, on_alrm);
- X alarm(2);
- X read (0, seqa+1, l-1);
- X alarm(0);
- X if (got_alrm)
- X return (c);
- X }
- X seqa[l] = '\0';
- X if (strcmp (seqa, kl) == 0)
- X return ('h');
- X if (strcmp (seqa, kd) == 0)
- X return ('j');
- X if (strcmp (seqa, ku) == 0)
- X return ('k');
- X if (strcmp (seqa, kr) == 0)
- X return ('l');
- X }
- X return (c);
- X}
- X
- X/* do whatever might be necessary to get the screen and/or tty back into shape.
- X */
- Xbyetty()
- X{
- X ioctl (0, TIOCSETP, &orig_sgtty);
- X#ifdef USE_NDELAY
- X fcntl (0, F_SETFL, 0); /* be sure to go back to blocking read */
- X#endif
- X}
- X
- Xstatic
- Xtload()
- X{
- X extern char *getenv(), *tgetstr();
- X extern char *UP, *BC;
- X char *egetstr();
- X static char tbuf[512];
- X char rawtbuf[1024];
- X char *tp;
- X char *ptr;
- X
- X if (!(tp = getenv ("TERM"))) {
- X printf ("Must have addressable cursor\n");
- X exit(1);
- X }
- X
- X if (!ttysetup) setuptty();
- X if (tgetent (rawtbuf, tp) != 1) {
- X printf ("Can't find termcap for %s\n", tp);
- X exit (1);
- X }
- X ptr = tbuf;
- X ku = egetstr ("ku", &ptr);
- X kd = egetstr ("kd", &ptr);
- X kl = egetstr ("kl", &ptr);
- X kr = egetstr ("kr", &ptr);
- X cm = egetstr ("cm", &ptr);
- X ce = egetstr ("ce", &ptr);
- X cl = egetstr ("cl", &ptr);
- X UP = egetstr ("up", &ptr);
- X if (!tgetflag ("bs"))
- X BC = egetstr ("bc", &ptr);
- X tloaded = 1;
- X}
- X
- X/* like tgetstr() but discard curses delay codes, for now anyways */
- Xstatic char *
- Xegetstr (name, sptr)
- Xchar *name;
- Xchar **sptr;
- X{
- X extern char *tgetstr();
- X register char c, *s;
- X
- X s = tgetstr (name, sptr);
- X while (((c = *s) >= '0' && c <= '9') || c == '*')
- X s += 1;
- X return (s);
- X}
- X
- X/* set up tty for char-by-char read, non-blocking */
- Xstatic
- Xsetuptty()
- X{
- X struct sgttyb sg;
- X
- X ioctl (0, TIOCGETP, &orig_sgtty);
- X sg = orig_sgtty;
- X sg.sg_flags &= ~ECHO; /* do our own echoing */
- X sg.sg_flags &= ~CRMOD; /* leave CR and LF unchanged */
- X sg.sg_flags |= XTABS; /* no tabs with termcap */
- X sg.sg_flags |= CBREAK; /* wake up on each char but can still kill */
- X ioctl (0, TIOCSETP, &sg);
- X ttysetup = 1;
- X}
- X#endif
- X
- X#ifdef TURBO_C
- X#ifdef USE_ANSISYS
- X#define ESC '\033'
- X/* position cursor.
- X * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
- X */
- Xc_pos (r, c)
- Xint r, c;
- X{
- X printf ("%c[%d;%df", ESC, r, c);
- X}
- X
- X/* erase entire screen. (ANSI: ESC [ 2 J) */
- Xc_erase()
- X{
- X printf ("%c[2J", ESC);
- X}
- X
- X/* erase to end of line. (ANSI: ESC [ K) */
- Xc_eol()
- X{
- X printf ("%c[K", ESC);
- X}
- X#else
- X#include <dos.h>
- Xunion REGS rg;
- X
- X/* position cursor.
- X */
- Xc_pos (r, c)
- Xint r, c;
- X{
- X rg.h.ah = 2;
- X rg.h.bh = 0;
- X rg.h.dh = r-1;
- X rg.h.dl = c-1;
- X int86(16,&rg,&rg);
- X}
- X
- X/* erase entire screen. */
- Xc_erase()
- X{
- X int cur_cursor, i;
- X rg.h.ah = 3;
- X rg.h.bh = 0;
- X int86(16,&rg,&rg);
- X cur_cursor = rg.x.dx;
- X for(i = 0; i < 25; i++){
- X c_pos(i+1,1);
- X rg.h.ah = 10;
- X rg.h.bh = 0;
- X rg.h.al = 32;
- X rg.x.cx = 80;
- X int86(16,&rg,&rg);
- X }
- X rg.h.ah = 2;
- X rg.h.bh = 0;
- X rg.x.dx = cur_cursor;
- X int86(16,&rg,&rg);
- X
- X}
- X
- X/* erase to end of line.*/
- Xc_eol()
- X{
- X int cur_cursor, i;
- X rg.h.ah = 3;
- X rg.h.bh = 0;
- X int86(16,&rg,&rg);
- X cur_cursor = rg.x.dx;
- X rg.h.ah = 10;
- X rg.h.bh = 0;
- X rg.h.al = 32;
- X rg.x.cx = 80 - rg.h.dl;
- X int86(16,&rg,&rg);
- X rg.h.ah = 2;
- X rg.h.bh = 0;
- X rg.x.dx = cur_cursor;
- X int86(16,&rg,&rg);
- X
- X}
- X#endif
- X
- X/* return 0 if there is a char that may be read without blocking, else -1 */
- Xchk_char()
- X{
- X return (kbhit() == 0 ? -1 : 0);
- X}
- X
- X/* read the next char, blocking if necessary, and return it. don't echo.
- X * map the arrow keys if we can too into hjkl
- X */
- Xread_char()
- X{
- X int c;
- X fflush (stdout);
- X c = getch();
- X if (c == 0) {
- X /* get scan code; convert to direction hjkl if possible */
- X c = getch();
- X switch (c) {
- X case 0x4b: c = 'h'; break;
- X case 0x50: c = 'j'; break;
- X case 0x48: c = 'k'; break;
- X case 0x4d: c = 'l'; break;
- X }
- X }
- X return (c);
- X}
- X
- X/* do whatever might be necessary to get the screen and/or tty back into shape.
- X */
- Xbyetty()
- X{
- X}
- X#endif
- X
- X/* read up to max chars into buf, with cannonization.
- X * add trailing '\0' (buf is really max+1 chars long).
- X * return count of chars read (not counting '\0').
- X * assume cursor is already positioned as desired.
- X * if type END when n==0 then return -1.
- X */
- Xread_line (buf, max)
- Xchar buf[];
- Xint max;
- X{
- X static char erase[] = "\b \b";
- X int n, c;
- X int done;
- X
- X#ifdef UNIX
- X if (!ttysetup) setuptty();
- X#endif
- X
- X for (done = 0, n = 0; !done; )
- X switch (c = read_char()) { /* does not echo */
- X case cntrl('h'): /* backspace or */
- X case 0177: /* delete are each char erase */
- X if (n > 0) {
- X fputs (erase, stdout);
- X n -= 1;
- X }
- X break;
- X case cntrl('u'): /* line erase */
- X while (n > 0) {
- X fputs (erase, stdout);
- X n -= 1;
- X }
- X break;
- X case '\r': /* EOL */
- X done++;
- X break;
- X default: /* echo and store, if ok */
- X if (n == 0 && c == END)
- X return (-1);
- X if (n >= max)
- X putchar (cntrl('g'));
- X else if (c >= ' ') {
- X putchar (c);
- X buf[n++] = c;
- X }
- X }
- X
- X buf[n] = '\0';
- X return (n);
- X}
- EOFxEOF
- len=`wc -c < io.c`
- if expr $len != 8533 > /dev/null
- then echo Length of io.c is $len but it should be 8533.
- fi
- echo x main.c
- sed -e 's/^X//' << 'EOFxEOF' > main.c
- X/* main "ephem" program.
- X * -------------------------------------------------------------------
- X * Copyright (c) 1990 by Elwood Charles Downey
- X *
- X * Permission is granted to make and distribute copies of this program
- X * free of charge, provided the copyright notice and this permission
- X * notice are preserved on all copies. All other rights reserved.
- X * -------------------------------------------------------------------
- X * set options.
- X * init screen and circumstances.
- X * enter infinite loop updating screen and allowing operator input.
- X */
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#include <math.h>
- X#include "astro.h"
- X#include "circum.h"
- X#include "screen.h"
- X
- Xextern char *getenv();
- Xextern char *strcpy();
- X
- X/* shorthands for fields of a Now structure, now.
- X * first undo the ones for a Now pointer from circum.h.
- X */
- X#undef mjd
- X#undef lat
- X#undef lng
- X#undef tz
- X#undef temp
- X#undef pressure
- X#undef height
- X#undef epoch
- X#undef tznm
- X
- X#define mjd now.n_mjd
- X#define lat now.n_lat
- X#define lng now.n_lng
- X#define tz now.n_tz
- X#define temp now.n_temp
- X#define pressure now.n_pressure
- X#define height now.n_height
- X#define epoch now.n_epoch
- X#define tznm now.n_tznm
- X
- Xstatic char *cfgfile = "ephem.cfg"; /* default config filename */
- X
- Xstatic Now now; /* where when and how, right now */
- Xstatic double tminc; /* hrs to inc time by each loop; RTC means use clock */
- Xstatic int nstep; /* steps to go before stopping */
- Xstatic int optwi; /* set when want to display dawn/dusk/len-of-night */
- Xstatic int oppl; /* mask of (1<<planet) bits; set when want to show it */
- X
- Xmain (ac, av)
- Xint ac;
- Xchar *av[];
- X{
- X void bye();
- X static char freerun[] =
- X "Running... press any key to stop to make changes.";
- X static char prmpt[] =
- X"Move to another field, RETURN to change this field, ? for help, or q to run";
- X static char hlp[] =
- X "arrow keys move to field; any key stops running; ^d exits; ^l redraws";
- X int curr = R_NSTEP, curc = C_NSTEPV; /* must start somewhere */
- X int sflag = 0; /* not silent, by default */
- X int one = 1; /* use a variable so optimizer doesn't get disabled */
- X int srchdone = 0; /* true when search funcs say so */
- X int newcir = 2; /* set when circumstances change - means don't tminc */
- X
- X while ((--ac > 0) && (**++av == '-')) {
- X char *s;
- X for (s = *av+1; *s != '\0'; s++)
- X switch (*s) {
- X case 's': /* no credits "silent" (don't publish this) */
- X sflag++;
- X break;
- X case 'c': /* set name of config file to use */
- X if (--ac <= 0) usage("-c but no config file");
- X cfgfile = *++av;
- X break;
- X default:
- X usage("Bad - option");
- X }
- X }
- X
- X if (!sflag)
- X credits();
- X
- X /* fresh screen.
- X * crack config file, THEN args so args may override.
- X */
- X c_erase();
- X read_cfgfile (cfgfile);
- X read_fieldargs (ac, av);
- X
- X /* set up to clean up screen and tty if interrupted */
- X signal (SIGINT, bye);
- X
- X /* update screen forever (until QUIT) */
- X while (one) {
- X
- X nstep -= 1;
- X
- X /* recalculate everything and update all the fields */
- X redraw_screen (newcir);
- X mm_newcir (0);
- X
- X /* let searching functions change tminc and check for done */
- X srchdone = srch_eval (mjd, &tminc) < 0;
- X print_tminc(0); /* to show possibly new search increment */
- X
- X /* update plot file, now that all fields are up to date and
- X * search function has been evaluated.
- X */
- X plot();
- X
- X /* stop loop to allow op to change parameters:
- X * if a search evaluation converges (or errors out),
- X * or if steps are done,
- X * or if op hits any key.
- X */
- X newcir = 0;
- X if (srchdone || nstep <= 0 || (chk_char()==0 && read_char()!=0)) {
- X int fld;
- X
- X /* update screen with the current stuff if stopped during
- X * unattended plotting since last redraw_screen() didn't.
- X */
- X if (plot_ison() && nstep > 0)
- X redraw_screen (1);
- X
- X /* return nstep to default of 1 */
- X if (nstep <= 0) {
- X nstep = 1;
- X print_nstep (0);
- X }
- X
- X /* change fields until END.
- X * update all time fields if any are changed
- X * and print NEW CIRCUMSTANCES if any have changed.
- X * QUIT causes bye() to be called and we never return.
- X */
- X while(fld = sel_fld(curr,curc,alt_menumask()|F_CHG,prmpt,hlp)) {
- X if (chg_fld ((char *)0, fld)) {
- X mm_now (&now, 1);
- X mm_newcir(1);
- X newcir = 1;
- X }
- X curr = unpackr (fld);
- X curc = unpackc (fld);
- X }
- X if (nstep > 1)
- X f_prompt (freerun);
- X }
- X
- X /* increment time only if op didn't change cirumstances */
- X if (!newcir)
- X inc_mjd (&now, tminc);
- X }
- X
- X return (0);
- X}
- X
- X/* draw all the stuff on the screen, using the current menu.
- X * if how_much == 0 then just update fields that need it;
- X * if how_much == 1 then redraw all fields;
- X * if how_much == 2 then erase the screen and redraw EVERYTHING.
- X */
- Xredraw_screen (how_much)
- Xint how_much;
- X{
- X if (how_much == 2)
- X c_erase();
- X
- X /* print the single-step message if this is the last loop */
- X if (nstep < 1)
- X print_updating();
- X
- X if (how_much == 2) {
- X mm_borders();
- X mm_labels();
- X srch_prstate(1);
- X plot_prstate(1);
- X alt_labels();
- X }
- X
- X /* if just updating changed fields while plotting unattended then
- X * suppress most screen updates except
- X * always show nstep to show plot loops to go and
- X * always show tminc to show search convergence progress.
- X */
- X print_nstep(how_much);
- X print_tminc(how_much);
- X if (how_much == 0 && plot_ison() && nstep > 0)
- X f_off();
- X
- X /* print all the time-related fields */
- X mm_now (&now, how_much);
- X
- X if (optwi)
- X mm_twilight (&now, how_much);
- X
- X /* print solar system body info */
- X print_bodies (how_much);
- X
- X f_on();
- X}
- X
- X/* clean up and exit for sure.
- X */
- Xvoid
- Xbye()
- X{
- X c_erase();
- X byetty();
- X exit (0);
- X}
- X
- Xstatic
- Xusage(why)
- Xchar *why;
- X{
- X /* don't advertise -s (silent) option */
- X c_erase();
- X f_string (1, 1, why);
- X f_string (2, 1, "usage: [-c <configfile>] [field=value] ...\r\n");
- X byetty();
- X exit (1);
- X}
- X
- X/* read cfg file, fn, if present.
- X * if errors in file, call usage() (which exits).
- X * try $HOME/.ephemrc as last resort.
- X * skip blank lines and lines that begin with '#', '*', ' ' or '\t'.
- X */
- Xstatic
- Xread_cfgfile(fn)
- Xchar *fn;
- X{
- X char buf[128];
- X FILE *fp;
- X
- X fp = fopen (fn, "r");
- X if (!fp) {
- X char *home = getenv ("HOME");
- X if (home) {
- X sprintf (buf, "%s/.ephemrc", home);
- X fp = fopen (buf, "r");
- X if (!fp)
- X return; /* oh well */
- X fn = buf; /* save fn for error report */
- X }
- X }
- X
- X while (fgets (buf, sizeof(buf), fp)) {
- X switch (buf[0]) {
- X case '#': case '*': case ' ': case '\t': case '\n':
- X continue;
- X }
- X buf[strlen(buf)-1] = '\0'; /* discard trailing \n */
- X if (crack_fieldset (buf) < 0) {
- X char why[128];
- X sprintf (why, "Unknown field spec in %s: %s\n", fn, buf);
- X usage (why);
- X }
- X }
- X fclose (fp);
- X}
- X
- X/* process the field specs from the command line.
- X * if trouble call usage() (which exits).
- X */
- Xstatic
- Xread_fieldargs (ac, av)
- Xint ac; /* number of such specs */
- Xchar *av[]; /* array of strings in form <field_name value> */
- X{
- X while (--ac >= 0) {
- X char *fs = *av++;
- X if (crack_fieldset (fs) < 0) {
- X char why[128];
- X sprintf (why, "Unknown command line field spec: %s", fs);
- X usage (why);
- X }
- X }
- X}
- X
- X/* process a field spec in buf, either from config file or argv.
- X * return 0 if recognized ok, else -1.
- X */
- Xstatic
- Xcrack_fieldset (buf)
- Xchar *buf;
- X{
- X if (strncmp ("LAT", buf, 3) == 0)
- X (void) chg_fld (buf+4, rcfpack (R_LAT,C_LATV,0));
- X else if (strncmp ("LONG", buf, 4) == 0)
- X (void) chg_fld (buf+5, rcfpack (R_LONG,C_LONGV,0));
- X else if (strncmp ("UT", buf, 2) == 0)
- X (void) chg_fld (buf+3, rcfpack (R_UT,C_UTV,0));
- X else if (strncmp ("UD", buf, 2) == 0)
- X (void) chg_fld (buf+3, rcfpack (R_UD,C_UD,0));
- X else if (strncmp ("TZONE", buf, 5) == 0)
- X (void) chg_fld (buf+6, rcfpack (R_TZONE,C_TZONEV,0));
- X else if (strncmp ("TZNAME", buf, 6) == 0)
- X (void) chg_fld (buf+7, rcfpack (R_TZN,C_TZN,0));
- X else if (strncmp ("HEIGHT", buf, 6) == 0)
- X (void) chg_fld (buf+7, rcfpack (R_HEIGHT,C_HEIGHTV,0));
- X else if (strncmp ("NSTEP", buf, 5) == 0)
- X (void) chg_fld (buf+6, rcfpack (R_NSTEP,C_NSTEPV,0));
- X else if (strncmp ("STPSZ", buf, 5) == 0)
- X (void) chg_fld (buf+6, rcfpack (R_STPSZ,C_STPSZV,0));
- X else if (strncmp ("TEMP", buf, 4) == 0)
- X (void) chg_fld (buf+5, rcfpack (R_TEMP,C_TEMPV,0));
- X else if (strncmp ("PRES", buf, 4) == 0)
- X (void) chg_fld (buf+5, rcfpack (R_PRES,C_PRESV,0));
- X else if (strncmp ("EPOCH", buf, 5) == 0)
- X (void) chg_fld (buf+6, rcfpack (R_EPOCH,C_EPOCHV,0));
- X else if (strncmp ("JD", buf, 2) == 0)
- X (void) chg_fld (buf+3, rcfpack (R_JD,C_JDV,0));
- X else if (strncmp ("OBJX", buf, 4) == 0)
- X (void) objx_define (buf+5);
- X else if (strncmp ("PROPTS", buf, 6) == 0) {
- X char *bp = buf+7;
- X if (buf[6] != '+')
- X optwi = oppl = 0;
- X while (*bp)
- X switch (*bp++) {
- X case 'T': optwi = 1; break;
- X case 'S': oppl |= (1<<SUN); break;
- X case 'M': oppl |= (1<<MOON); break;
- X case 'e': oppl |= (1<<MERCURY); break;
- X case 'v': oppl |= (1<<VENUS); break;
- X case 'm': oppl |= (1<<MARS); break;
- X case 'j': oppl |= (1<<JUPITER); break;
- X case 's': oppl |= (1<<SATURN); break;
- X case 'u': oppl |= (1<<URANUS); break;
- X case 'n': oppl |= (1<<NEPTUNE); break;
- X case 'p': oppl |= (1<<PLUTO); break;
- X case 'x': oppl |= (1<<OBJX); objx_on(); break;
- X }
- X } else
- X return (-1);
- X return (0);
- X}
- X
- X/* change the field at rcpk according to the optional string input at bp.
- X * if bp is != 0 use it, else issue read_line() and use buffer.
- X * then sscanf the buffer and update the corresponding (global) variable(s)
- X * or do whatever a pick at that field should do.
- X * return 1 if we change a field that invalidates any of the times or
- X * to update all related fields.
- X */
- Xstatic
- Xchg_fld (bp, rcpk)
- Xchar *bp;
- Xint rcpk;
- X{
- X char buf[NC];
- X int deghrs = 0, mins = 0, secs = 0;
- X int new = 0;
- X
- X /* switch on just the row/col portion */
- X switch (unpackrc(rcpk)) {
- X case rcfpack (R_ALTM, C_ALTM, 0):
- X if (altmenu_setup() == 0) {
- X print_updating();
- X alt_nolabels();
- X clrall_bodies();
- X alt_labels();
- X print_bodies(1);
- X }
- X break;
- X case rcfpack (R_JD, C_JDV, 0):
- X if (!bp) {
- X static char p[] = "Julian Date (or n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else
- X mjd = atof(bp) - 2415020L;
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_UD, C_UD, 0):
- X if (!bp) {
- X static char p[] = "utc date (m/d/y, or year.d, or n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else {
- X if (decimal_year(bp)) {
- X double y = atof (bp);
- X year_mjd (y, &mjd);
- X } else {
- X double day, newmjd0;
- X int month, year;
- X mjd_cal (mjd, &month, &day, &year); /* init with now */
- X f_sscandate (bp, &month, &day, &year);
- X cal_mjd (month, day, year, &newmjd0);
- X /* if don't give a fractional part to days
- X * then retain current hours.
- X */
- X if ((long)day == day)
- X mjd = newmjd0 + mjd_hr(mjd)/24.0;
- X else
- X mjd = newmjd0;
- X }
- X }
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_UT, C_UTV, 0):
- X if (!bp) {
- X static char p[] = "utc time (h:m:s, or n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else {
- X double newutc = (mjd-mjd_day(mjd)) * 24.0;
- X f_dec_sexsign (newutc, °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &newutc);
- X mjd = mjd_day(mjd) + newutc/24.0;
- X }
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_LD, C_LD, 0):
- X if (!bp) {
- X static char p[] = "local date (m/d/y, or year.d, n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else {
- X if (decimal_year(bp)) {
- X double y = atof (bp);
- X year_mjd (y, &mjd);
- X mjd += tz/24.0;
- X } else {
- X double day, newlmjd0;
- X int month, year;
- X mjd_cal (mjd-tz/24.0, &month, &day, &year); /* now */
- X f_sscandate (bp, &month, &day, &year);
- X cal_mjd (month, day, year, &newlmjd0);
- X /* if don't give a fractional part to days
- X * then retain current hours.
- X */
- X if ((long)day == day)
- X mjd = newlmjd0 + mjd_hr(mjd-tz/24.0)/24.0;
- X else
- X mjd = newlmjd0;
- X mjd += tz/24.0;
- X }
- X }
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_LT, C_LT, 0):
- X if (!bp) {
- X static char p[] = "local time (h:m:s, or n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else {
- X double newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
- X range (&newlt, 24.0);
- X f_dec_sexsign (newlt, °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &newlt);
- X mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
- X }
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_LST, C_LSTV, 0):
- X if (!bp) {
- X static char p[] = "local sidereal time (h:m:s, or n for Now): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'n' || bp[0] == 'N')
- X time_fromsys (&now);
- X else {
- X double lst, utc;
- X now_lst (&now, &lst);
- X f_dec_sexsign (lst, °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &lst);
- X lst -= radhr(lng); /* convert to gst */
- X range (&lst, 24.0);
- X gst_utc (mjd_day(mjd), lst, &utc);
- X mjd = mjd_day(mjd) + utc/24.0;
- X }
- X set_t0 (&now);
- X new = 1;
- X break;
- X case rcfpack (R_TZN, C_TZN, 0):
- X if (!bp) {
- X static char p[] = "timezone abbreviation (3 char max): ";
- X f_prompt (p);
- X if (read_line (buf, 3) <= 0)
- X break;
- X bp = buf;
- X }
- X strcpy (tznm, bp);
- X new = 1;
- X break;
- X case rcfpack (R_TZONE, C_TZONEV, 0):
- X if (!bp) {
- X static char p[] = "hours behind utc: ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X f_dec_sexsign (tz, °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &tz);
- X new = 1;
- X break;
- X case rcfpack (R_LONG, C_LONGV, 0):
- X if (!bp) {
- X static char p[] = "longitude (+ west) (d:m:s): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X f_dec_sexsign (-raddeg(lng), °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &lng);
- X lng = degrad (-lng); /* want - radians west */
- X new = 1;
- X break;
- X case rcfpack (R_LAT, C_LATV, 0):
- X if (!bp) {
- X static char p[] = "latitude (+ north) (d:m:s): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X f_dec_sexsign (raddeg(lat), °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &lat);
- X lat = degrad (lat);
- X new = 1;
- X break;
- X case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
- X if (!bp) {
- X static char p[] = "height above sea level (ft): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X sscanf (bp, "%lf", &height);
- X height /= 2.093e7; /* convert ft to earth radii above sea level */
- X new = 1;
- X break;
- X case rcfpack (R_NSTEP, C_NSTEPV, 0):
- X if (!bp) {
- X static char p[] = "number of steps to run: ";
- X f_prompt (p);
- X if (read_line (buf, 8) <= 0)
- X break;
- X bp = buf;
- X }
- X sscanf (bp, "%d", &nstep);
- X print_nstep (0);
- X break;
- X case rcfpack (R_TEMP, C_TEMPV, 0):
- X if (!bp) {
- X static char p[] = "temperature (deg.F): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X sscanf (bp, "%lf", &temp);
- X temp = 5./9.*(temp - 32.0); /* want degs C */
- X new = 1;
- X break;
- X case rcfpack (R_PRES, C_PRESV, 0):
- X if (!bp) {
- X static char p[] =
- X "atmos pressure (in. Hg; 0 for no refraction correction): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X sscanf (bp, "%lf", &pressure);
- X pressure *= 33.86; /* want mBar */
- X new = 1;
- X break;
- X case rcfpack (R_EPOCH, C_EPOCHV, 0):
- X if (!bp) {
- X static char p[] = "epoch (year, or e for Equinox of Date): ";
- X f_prompt (p);
- X if (read_line (buf, PW-strlen(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'e' || bp[0] == 'E')
- X epoch = EOD;
- X else {
- X double e;
- X e = atof(bp);
- X year_mjd (e, &epoch);
- X }
- X new = 1;
- X break;
- X case rcfpack (R_STPSZ, C_STPSZV, 0):
- X if (!bp) {
- X static char p[] =
- X "step size increment (h:m:s, or <x>d for x days, or r for RTC): ";
- X f_prompt (p);
- X if (read_line (buf, PW-sizeof(p)) <= 0)
- X break;
- X bp = buf;
- X }
- X if (bp[0] == 'r' || bp[0] == 'R')
- X tminc = RTC;
- X else {
- X int last = strlen (bp) - 1;
- X if (bp[last] == 'd') {
- X /* ends in d so treat as a number of days */
- X double x;
- X sscanf (bp, "%lf", &x);
- X tminc = x * 24.0;
- X } else {
- X if (tminc == RTC)
- X deghrs = mins = secs = 0;
- X else
- X f_dec_sexsign (tminc, °hrs, &mins, &secs);
- X f_sscansex (bp, °hrs, &mins, &secs);
- X sex_dec (deghrs, mins, secs, &tminc);
- X }
- X }
- X print_tminc(0);
- X set_t0 (&now);
- X break;
- X case rcfpack (R_PLOT, C_PLOT, 0):
- X plot_setup();
- X if (plot_ison())
- X new = 1;
- X break;
- X case rcfpack (R_WATCH, C_WATCH, 0):
- X watch (&now, tminc, oppl);
- X /* set new reference time to what watch left it.
- X * no need to set new since watch just did a redraw.
- X */
- X set_t0 (&now);
- X break;
- X case rcfpack (R_DAWN, C_DAWN, 0):
- X case rcfpack (R_DUSK, C_DUSK, 0):
- X case rcfpack (R_LON, C_LON, 0):
- X if (optwi ^= 1) {
- X print_updating();
- X mm_twilight (&now, 1);
- X } else {
- X f_blanks (R_DAWN, C_DAWNV, 5);
- X f_blanks (R_DUSK, C_DUSKV, 5);
- X f_blanks (R_LON, C_LONV, 5);
- X }
- X break;
- X case rcfpack (R_SRCH, C_SRCH, 0):
- X srch_setup();
- X if (srch_ison())
- X new = 1;
- X break;
- X case rcfpack (R_SUN, C_OBJ, 0):
- X if ((oppl ^= (1<<SUN)) & (1<<SUN)) {
- X print_updating();
- X alt_body (SUN, 1, &now);
- X } else
- X alt_nobody (SUN);
- X break;
- X case rcfpack (R_MOON, C_OBJ, 0):
- X if ((oppl ^= (1<<MOON)) & (1<<MOON)) {
- X print_updating();
- X alt_body (MOON, 1, &now);
- X } else
- X alt_nobody (MOON);
- X break;
- X case rcfpack (R_MERCURY, C_OBJ, 0):
- X if ((oppl ^= (1<<MERCURY)) & (1<<MERCURY)) {
- X print_updating();
- X alt_body (MERCURY, 1, &now);
- X } else
- X alt_nobody (MERCURY);
- X break;
- X case rcfpack (R_VENUS, C_OBJ, 0):
- X if ((oppl ^= (1<<VENUS)) & (1<<VENUS)) {
- X print_updating();
- X alt_body (VENUS, 1, &now);
- X } else
- X alt_nobody (VENUS);
- X break;
- X case rcfpack (R_MARS, C_OBJ, 0):
- X if ((oppl ^= (1<<MARS)) & (1<<MARS)) {
- X print_updating();
- X alt_body (MARS, 1, &now);
- X } else
- X alt_nobody (MARS);
- X break;
- X case rcfpack (R_JUPITER, C_OBJ, 0):
- X if ((oppl ^= (1<<JUPITER)) & (1<<JUPITER)) {
- X print_updating();
- X alt_body (JUPITER, 1, &now);
- X } else
- X alt_nobody (JUPITER);
- X break;
- X case rcfpack (R_SATURN, C_OBJ, 0):
- X if ((oppl ^= (1<<SATURN)) & (1<<SATURN)) {
- X print_updating();
- X alt_body (SATURN, 1, &now);
- X } else
- X alt_nobody (SATURN);
- X break;
- X case rcfpack (R_URANUS, C_OBJ, 0):
- X if ((oppl ^= (1<<URANUS)) & (1<<URANUS)) {
- X print_updating();
- X alt_body (URANUS, 1, &now);
- X } else
- X alt_nobody (URANUS);
- X break;
- X case rcfpack (R_NEPTUNE, C_OBJ, 0):
- X if ((oppl ^= (1<<NEPTUNE)) & (1<<NEPTUNE)) {
- X print_updating();
- X alt_body (NEPTUNE, 1, &now);
- X } else
- X alt_nobody (NEPTUNE);
- X break;
- X case rcfpack (R_PLUTO, C_OBJ, 0):
- X if ((oppl ^= (1<<PLUTO)) & (1<<PLUTO)) {
- X print_updating();
- X alt_body (PLUTO, 1, &now);
- X } else
- X alt_nobody (PLUTO);
- X break;
- X case rcfpack (R_OBJX, C_OBJ, 0):
- X /* this might change which columns are used so erase all when
- X * returns and redraw if still on.
- X */
- X objx_setup ();
- X alt_nobody (OBJX);
- X if (objx_ison()) {
- X oppl |= 1 << OBJX;
- X print_updating();
- X alt_body (OBJX, 1, &now);
- X } else
- X oppl &= ~(1 << OBJX); /* already erased; just clear flag */
- X break;
- X }
- X
- X return (new);
- X}
- X
- Xstatic
- Xprint_tminc(force)
- Xint force;
- X{
- X static double last;
- X
- X if (force || tminc != last) {
- X if (tminc == RTC)
- X f_string (R_STPSZ, C_STPSZV, " RT CLOCK");
- X else if (fabs(tminc) >= 24.0)
- X f_double (R_STPSZ, C_STPSZV, "%6.4g dy", tminc/24.0);
- X else
- X f_signtime (R_STPSZ, C_STPSZV, tminc);
- X last = tminc;
- X }
- X}
- X
- Xstatic
- Xprint_bodies (force)
- Xint force;
- X{
- X int p;
- X
- X for (p = nxtbody(-1); p != -1; p = nxtbody(p))
- X if (oppl & (1<<p))
- X alt_body (p, force, &now);
- X}
- X
- Xstatic
- Xclrall_bodies ()
- X{
- X int p;
- X
- X for (p = nxtbody(-1); p != -1; p = nxtbody(p))
- X if (oppl & (1<<p))
- X alt_nobody (p);
- X}
- X
- Xprint_updating()
- X{
- X f_prompt ("Updating...");
- X}
- X
- Xstatic
- Xprint_nstep(force)
- Xint force;
- X{
- X static int last;
- X
- X if (force || nstep != last) {
- X char buf[16];
- X sprintf (buf, "%8d", nstep);
- X f_string (R_NSTEP, C_NSTEPV, buf);
- X last = nstep;
- X }
- X}
- EOFxEOF
- len=`wc -c < main.c`
- if expr $len != 21224 > /dev/null
- then echo Length of main.c is $len but it should be 21224.
- fi
-
-